﻿/*
  In App.xaml:
  <Application.Resources>
      <vm:ViewModelLocatorTemplate xmlns:vm="clr-namespace:DepSoft.Mobile.WP7.FollowIt.ViewModel"
                                   x:Key="Locator" />
  </Application.Resources>
  
  In the View:
  DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}"
  
  OR (WPF only):
  
  xmlns:vm="clr-namespace:DepSoft.Mobile.WP7.FollowIt.ViewModel"
  DataContext="{Binding Source={x:Static vm:ViewModelLocatorTemplate.ViewModelNameStatic}}"
*/

using System;
using System.Collections.Generic;
using Microsoft.Phone.Shell;
namespace DepSoft.Mobile.WP7.FollwIt.ViewModel
{
    /// <summary>
    /// This class contains static references to all the view models in the
    /// application and provides an entry point for the bindings.
    /// <para>
    /// Use the <strong>mvvmlocatorproperty</strong> snippet to add ViewModels
    /// to this locator.
    /// </para>
    /// <para>
    /// In Silverlight and WPF, place the ViewModelLocatorTemplate in the App.xaml resources:
    /// </para>
    /// <code>
    /// &lt;Application.Resources&gt;
    ///     &lt;vm:ViewModelLocatorTemplate xmlns:vm="clr-namespace:DepSoft.Mobile.WP7.FollowIt.ViewModel"
    ///                                  x:Key="Locator" /&gt;
    /// &lt;/Application.Resources&gt;
    /// </code>
    /// <para>
    /// Then use:
    /// </para>
    /// <code>
    /// DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}"
    /// </code>
    /// <para>
    /// You can also use Blend to do all this with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// <para>
    /// In <strong>*WPF only*</strong> (and if databinding in Blend is not relevant), you can delete
    /// the Main property and bind to the ViewModelNameStatic property instead:
    /// </para>
    /// <code>
    /// xmlns:vm="clr-namespace:DepSoft.Mobile.WP7.FollowIt.ViewModel"
    /// DataContext="{Binding Source={x:Static vm:ViewModelLocatorTemplate.ViewModelNameStatic}}"
    /// </code>
    /// </summary>
    public class ViewModelLocator : IDisposable
    {
        #region Private members
        /// <summary>
        /// The boot strapper.
        /// </summary>
        private readonly BootStrapper bootStrapper;

        /// <summary>
        /// The disposed.
        /// </summary>
        private bool disposed;

        /// <summary>
        /// The resolved instances.
        /// </summary>
        private IDictionary<Type, ViewModelInstance> resolvedInstances = new Dictionary<Type, ViewModelInstance>();
        #endregion

        #region Public members
        public static readonly Uri MainPageUri = new Uri("/View/MainPage.xaml", UriKind.Relative);
        public static readonly Uri CollectionPageUri = new Uri("/View/CollectionPage.xaml", UriKind.Relative);
        public static readonly Uri UserProfilePageUri = new Uri("/View/UserProfilePage.xaml", UriKind.Relative);
        public static readonly Uri MovieSummaryPageUri = new Uri("/View/MovieSummaryPage.xaml", UriKind.Relative);
        public static readonly Uri TVShowSummaryPageUri = new Uri("/View/TVShowSummaryPage.xaml", UriKind.Relative);
        public static readonly Uri SettingsPageUri = new Uri("/View/SettingsPage.xaml", UriKind.Relative);
        //public static readonly Uri AboutPageUri = new Uri("/View/AboutPage.xaml", UriKind.Relative);
        #endregion

        #region Public properties
        /// <summary>
        /// Get MainViewModel
        /// </summary>
        public MainViewModel MainViewModel
        {
            get
            {
                return this.ResolveInstance<MainViewModel>();
            }
        }

        /// <summary>
        /// Get CollectionViewModel
        /// </summary>
        public CollectionViewModel CollectionViewModel
        {
            get
            {
                return this.ResolveInstance<CollectionViewModel>();
            }
        }

        /// <summary>
        /// Get UserProfileViewModel
        /// </summary>
        public UserProfileViewModel UserProfileViewModel
        {
            get
            {
                return this.ResolveInstance<UserProfileViewModel>();
            }
        }

        /// <summary>
        /// Get MovieSummaryViewModel
        /// </summary>
        public MovieSummaryViewModel MovieSummaryViewModel
        {
            get
            {
                return this.ResolveInstance<MovieSummaryViewModel>();
            }
        }

        /// <summary>
        /// Get TVShowSummaryViewModel
        /// </summary>
        public TVShowSummaryViewModel TVShowSummaryViewModel
        {
            get
            {
                return this.ResolveInstance<TVShowSummaryViewModel>();
            }
        }

        /// <summary>
        /// Get SettingsPivotViewModel
        /// </summary>
        public SettingsViewModel SettingsViewModel
        {
            get
            {
                return this.ResolveInstance<SettingsViewModel>();
            }
        }

        /// <summary>
        /// Get AboutViewModel
        /// </summary>
        //public AboutViewModel AboutViewModel
        //{
        //    get
        //    {
        //        return this.ResolveInstance<AboutViewModel>();
        //    }
        //}
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        public ViewModelLocator()
        {
            if (this.bootStrapper == null)
            {
                this.bootStrapper = new BootStrapper();
            }
        }
        #endregion

        #region Private methods
        /// <summary>
        /// The dispose.
        /// </summary>
        /// <param name="disposing">
        /// The disposing.
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            if (this.disposed)
            {
                return;
            }

            if (disposing)
            {
                this.resolvedInstances.Clear();
                this.resolvedInstances = null;

                this.bootStrapper.Dispose();
            }

            this.disposed = true;
        }

        /// <summary>
        /// The resolve instance.
        /// </summary>
        /// <typeparam name="T">
        /// </typeparam>
        /// <returns>
        /// </returns>
        private T ResolveInstance<T>() where T : ViewModelBaseWp7
        {
            if (this.resolvedInstances.ContainsKey(typeof(T)))
            {
                return (T)this.resolvedInstances[typeof(T)].ViewModel;
            }

            var viewModel = this.bootStrapper.Container.Resolve<T>();
            this.resolvedInstances.Add(viewModel.GetType(), new ViewModelInstance(viewModel));

            return viewModel;
        }
        #endregion

        #region IDisposable implementation
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

        /// <summary>
        /// The view model instance.
        /// </summary>
        internal class ViewModelInstance
        {
            #region Constructor
            /// <summary>
            /// Initializes a new instance of the <see cref="ViewModelInstance"/> class.
            /// </summary>
            /// <param name="viewModel">
            /// The view model.
            /// </param>
            public ViewModelInstance(ViewModelBaseWp7 viewModel)
            {
                this.ViewModel = viewModel;

                if (PhoneApplicationService.Current.StartupMode == StartupMode.Activate)
                {
                    this.ViewModel.Activate();
                }

                PhoneApplicationService.Current.Deactivated += this.HandleDeactivation;
            }
            #endregion

            #region Public properties
            /// <summary>
            /// Gets ViewModel.
            /// </summary>
            public ViewModelBaseWp7 ViewModel { get; private set; }
            #endregion

            #region Private methods
            /// <summary>
            /// The handle deactivation.
            /// </summary>
            /// <param name="s">
            /// The s.
            /// </param>
            /// <param name="e">
            /// The e.
            /// </param>
            private void HandleDeactivation(object s, DeactivatedEventArgs e)
            {
                this.ViewModel.Deactivate();
            }
            #endregion
        }
    }
}